`timescale 1ns / 100ps

module i2c_master (
	input clk,
	input rst_n,
	input [7:0] slave_addr,
	input [7:0] reg_addr,
	input [7:0] reg_value,
	
	inout scl,
	inout sda,
	output [7:0] reg_read_value
);

reg [7:0] reg_read_value;
reg scl_out;
reg scl_in;
reg sda_out;
reg sda_in;

assign scl = scl_out?1'bz:0;
assign sda = sda_out?1'bz:0;

reg [7:0] delay_count;
reg [7:0] state;
reg [7:0] g_state;


task i2c_start;
	case (state)
			// i2c_start
			0: begin
				sda_out <= 1;
				state <= 1;
			end
			1: begin
				scl_out <= 1;
				state <= 2;
			end
			2: begin
				if((scl_in == 1)&(sda_in == 1)) begin
					state <= 3;
				end
			end
			3: begin
				sda_out <= 0;
				state <= 4;
			end
			4: begin
				scl_out <= 0;
				state <= 5;
			end
		
	endcase
	

endtask

task i2c_stop;
	case (state)
			// i2c_stop
			0: begin
				scl_out <= 0;
				state <= 1;
			end
			1: begin
				sda_out <= 0;
				state <= 2;
			end
			2: begin
				scl_out <= 1;
				state <= 3;
			end
			3: begin
				sda_out <= 1;
				state <= 4;
			end		
	endcase
	

endtask

reg [7:0] sendByte;
reg [7:0] sendMask;

task i2c_SendByte;
	case (state)
		0, 4, 8,12,16,20,24,28: begin
			if(sendByte & sendMask) begin
				sda_out <= 1;
			end
			else begin
				sda_out <= 0;
			end
			state <= state+1;
		end
		1, 5, 9,13,17,21,25,29: begin
			scl_out <= 1;
			state <= state+1;
		end
		2, 6,10,14,18,22,26,30: begin
			scl_out <= 0;
			state <= state+1;
		end
		3, 7,11,15,19,23,27,31: begin
			sendMask <= sendMask>>1;
			state <= state+1;
		end
		32: begin
			sda_out <= 1;
			state <= state+1;
		end
		33: begin
			scl_out <= 1;
			state <= state+1;
		end
		34,35,36,37,38,39: begin
			if(sda_in) begin				
				state <= state+1;
			end
			else begin
				state <= 40;
			end		
		end
		40: begin
			scl_out <= 0;
		end
	endcase
endtask

task i2c_writeByte;
		case (g_state)
			// i2c_start
			0: begin
				i2c_start();
				if(state == 5) begin
					g_state <= g_state+1;
				end
			end
			// i2c_SendByte(slave_addr)
			1: begin
				state <= 0;
				sendByte <= slave_addr;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			2: begin
				i2c_SendByte();
				if(state == 40) begin
					g_state <= g_state+1;
				end
				
			end
			// i2c_SendByte(reg_addr)
			3: begin
				state <= 0;
				sendByte <= reg_addr;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			4: begin
				i2c_SendByte();
				if(state == 40) begin
					g_state <= g_state+1;
				end				
			end
			// i2c_SendByte(reg_value)
			5: begin
				state <= 0;
				sendByte <= reg_value;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			6: begin
				i2c_SendByte();
				if(state == 40) begin
					g_state <= g_state+1;
				end				
			end
			7: begin
				state <= 0;
				g_state <= g_state+1;
			end
			8: begin
				i2c_stop();
			end
		
		endcase
endtask

task i2c_ReceiveByte;
	case (state)
	0: begin
		sda_out <= 1;
		state <= state+1;
	end
	1: begin
		scl_out <= 1;
		state <= state+1;
	end
	2: begin
		state <= state+1;
	end
	3: begin
		if(sda_in) begin
			sendByte <= sendByte | sendMask;
		end
		scl_out <= 0;
		if(sendMask == 8'h01) begin
			state <= state+1;
		end
		else begin
			sendMask = sendMask >> 1;
			state <= 0;
		end
	end
	4: begin
		sda_out <= 0;
		state <= state+1;
	end
	5: begin
		scl_out <= 1;
		state <= state+1;
	end
	6: begin
		scl_out <= 0;
		state <= state+1;
	end
	
	endcase
endtask

task i2c_readByte;
		case (g_state)
			// i2c_start
			0: begin
				i2c_start();
				if(state == 5) begin
					g_state <= g_state+1;
				end
			end
			// i2c_SendByte(slave_addr&0xfe)
			1: begin
				state <= 0;
				sendByte <= slave_addr & 8'hFE;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			2: begin
				i2c_SendByte();
				if(state == 40) begin
					g_state <= g_state+1;
				end
				
			end
			// i2c_SendByte(reg_addr)
			3: begin
				state <= 0;
				sendByte <= reg_addr;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			4: begin
				i2c_SendByte();
				if(state == 40) begin
					g_state <= g_state+1;
				end				
			end
			// i2c_start
			5: begin
				state <= 0;
				g_state <= g_state+1;
			end
			6: begin
				i2c_start();
				if(state == 5) begin
					g_state <= g_state+1;
				end		
			end
			// i2c_SendByte(slave_addr|0x01)
			7: begin
				state <= 0;
				sendByte <= slave_addr | 8'h01;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			8: begin
				i2c_SendByte();
				if(state == 40) begin
					g_state <= g_state+1;
				end		
			end
			// i2c_ReceiveByte()
			9: begin
				state <= 0;
				sendByte <= 0;
				sendMask <= 8'h80;
				g_state <= g_state+1;
			end
			10: begin
				i2c_ReceiveByte();
				if(state == 7) begin
					g_state <= g_state+1;
					reg_read_value <= sendByte;
				end	
			end
			// i2c_stop
			11: begin
				state <= 0;
				g_state <= g_state+1;
			end
			12: begin
				i2c_stop();
			end
		
		endcase
endtask

always @ (posedge clk)
begin
	if(!rst_n) begin
		scl_out <= 1;
		sda_out <= 1;
		delay_count <= 0;
		state <= 0;
		g_state <= 0;
	end
	else begin
		scl_in <= scl;
		sda_in <= sda;
		if(slave_addr[0]) begin
			i2c_readByte();
		end
		else begin
			i2c_writeByte();
		end
		
		
	end

end



endmodule